Funções de uma variável real com valores vetoriais#
Vamos considerar funções do tipo
às vezes podemos escrever a função com uma seta acima, da forma \(\overrightarrow{F}\), para enfatizar que trata-se de uma função com valores vetoriais.
Show code cell source
# HIDE CODE
import plotly.express as px
import plotly.graph_objects as go
import numpy as np
Hélice#
Vamos começar com a curva conhecida como Hélice, que pode ser parametriada por \(\overrightarrow{F}(t) = \left(\cos(t), \text{sen}(t), t \right)\). Na figura abaixo podemos ver o traço com o parâmetro \(t\) percorrendo o intervalo \(0 \leqslant t \leqslant 6\pi\).
Show code cell source
# HIDE CODE
pontos = 100
t = np.linspace(0, 6*np.pi, pontos, endpoint=True)
x=np.cos(t)
y=np.sin(t)
z=t
fig2 = px.line_3d(x=x, y=y, z=z)
fig = px.scatter_3d(x=x, y=y, z=z, animation_frame=t, size = 12*np.ones(pontos),labels={'animation_frame':'t'}) # animação dos pontos da hélice
fig.add_trace(fig2.data[0]) # adicionar a curva
fig.layout.updatemenus[0].buttons[0].args[1]['frame']['duration'] = 0 # duração da transição da animação
fig.show()
Ciclóide#
Vejamos agora o exemplo de uma curva famosa, chamada ciclóide. É a curva gerada a partir da trajetória de um ponto sobre a circunferência que “anda” sobre uma linha reta sem deslizar.
Show code cell source
# HIDE CODE
#para mais detalhes de animação ver o exemplo mri https://plotly.com/python/visualizing-mri-volume-slices/
pontos = 100
teta = np.linspace(0, 4*np.pi, pontos, endpoint=True)
phi = np.linspace(0, 2*np.pi, pontos, endpoint=True)
x = teta - np.sin(teta)
y = 1 - np.cos(teta)
xmin = np.min(x)
xmax = np.max(x)
ymin = np.min(y)
ymax = np.max(y)
data = [go.Scatter(x=x,y= y,mode="lines", line=dict(color="red")), # Mostrar antes do início da animação
go.Scatter(),go.Scatter()] # outros traços (vazios) que serão modificados em cada frame
frames = [go.Frame(data = go.Scatter(x=teta[p] + np.cos(phi),y= 1 + np.sin(phi), #Adiciona a circunferencia que gira
showlegend=False, mode="lines", line=dict(color="blue")
),
name=str(p)
)
for p in range(pontos)
]
def frame_args(duration,transition): # tempo de duração e transição dos frames
return {
"frame": {"duration": duration},
"mode": "immediate",
"fromcurrent": True,
"transition": {"duration": transition, "easing": "linear"},
}
layout=go.Layout(
xaxis=dict(range=[xmin-1.2,xmax + 1.2], autorange=False, zeroline=False),
yaxis=dict(range=[ymin-0.5,ymax + 0.5], autorange=False, zeroline=False,
scaleanchor = "x",scaleratio = 1,), # gráfico em escala 1:1
title_text="Ciclóide", hovermode="closest",
updatemenus=[dict(type="buttons",
buttons=[dict(label= "▶", # play symbol,
method="animate",
args=[None,frame_args(0,0)])])])
for k in range(len(frames)): # Adiciona o ponto sobre a circunferência e traço deixado ao girar (cicloide)
tetap = np.linspace(0, teta[k], pontos, endpoint=True)
frames[k].data = frames[k].data + (go.Scatter(x = tetap - np.sin(tetap),y = 1 - np.cos(tetap),
showlegend=False,
marker=dict(color="red")
)
,)
frames[k].data = frames[k].data + (go.Scatter(x = [tetap[-1] - np.sin(tetap[-1])],y = [1 - np.cos(tetap[-1])],
showlegend=False,
mode="markers",
marker=dict(color="red", size=10)
)
,)
figura = go.Figure(data = data, layout = layout, frames = frames)
figura.show()
A ciclóide pode ser parametrizada por \(\overrightarrow{F}(\theta) = \left( \theta - \text{sen}(\theta), 1 - \cos(\theta) \right)\), vejamos abaixo o gráfico com o parâmetro \(\theta\) no intervalo \([0, 4\pi]\).
Show code cell source
# HIDE CODE
pontos = 100
teta = np.linspace(0, 4*np.pi, pontos, endpoint=True)
x = teta - np.sin(teta)
y = 1 - np.cos(teta)
xmin = np.min(x)
xmax = np.max(x)
ymin = np.min(y)
ymax = np.max(y)
fig = px.scatter(x=x, y=y, animation_frame=teta, labels={'animation_frame' : 'θ'})
fig.update_traces(marker=dict(size=12))
fig2 = px.line(x=x, y=y)
fig.add_trace(fig2.data[0])
fig.update_yaxes(scaleanchor = "x",scaleratio = 1,)
fig.update_xaxes(range=[xmin-0.5,xmax + 0.5])
fig.update_yaxes(range=[ymin-0.5,ymax + 0.5])
fig.layout.updatemenus[0].buttons[0].args[1]['frame']['duration'] = 40 # intervalo entre frames em ms, para controlar a duração da animação
fig.show()
Show code cell source
# HIDE CODE
pontos = 100
t = np.linspace(-1, 1, pontos)
x = t + t ** 2
y = t - t ** 2
s = np.linspace(-1, 1, pontos)
xx = (1 + 2*s)#/np.sqrt(2+4*s**2)
yy = (1 - 2*s)#/np.sqrt(2+4*s**2)
xm = np.min(np.concatenate((x,x+xx))) - 0.5
xM = np.max(np.concatenate((x,x+xx))) + 0.5
ym = np.min(np.concatenate((y,y+yy))) - 0.5
yM = np.max(np.concatenate((y,y+yy))) + 0.5
# Create figure
fig = go.Figure(
data=[go.Scatter(name = "",x=x, y=y,
mode="lines",
line=dict(width=2, color="blue")),
go.Scatter(name = "Curva",x=x, y=y,
mode="lines",
line=dict(width=2, color="blue"))],
layout=go.Layout(
xaxis=dict(range=[xm, xM], autorange=False, zeroline=False),
yaxis=dict(range=[ym, yM], autorange=False, zeroline=False),
title_text="Curva plana parametrizada", hovermode="closest",
updatemenus=[dict(type="buttons",
buttons=[dict(label="Play",
method="animate",
args=[None,{
"frame": {"duration": 20}}])])]),
frames=[go.Frame(
data=[go.Scatter(name = "Vetor tangente",
x=[x[k], x[k] + xx[k]],
y=[y[k], y[k] + yy[k]],
mode="lines+markers",
line=dict(color='red'),
marker=dict(color="red", size=20,symbol= "arrow",angleref="previous"))])
for k in range(pontos)]
)
fig.update_yaxes(scaleanchor = "x",scaleratio = 1,)
fig.show()
Show code cell source
# HIDE CODE
pontos = 300
t = np.linspace(0, 3*np.pi, pontos)
x = np.cos(t)
y = np.sin(t)
s = np.linspace(-1, 1, pontos)
xx = -np.sin(t)
yy = np.cos(t)
xm = np.min(np.concatenate((x,x+xx))) - 0.5
xM = np.max(np.concatenate((x,x+xx))) + 0.5
ym = np.min(np.concatenate((y,y+yy))) - 0.5
yM = np.max(np.concatenate((y,y+yy))) + 0.5
# Create figure
fig = go.Figure(
data=[go.Scatter(name = "",x=x, y=y,
mode="lines",
line=dict(width=2, color="blue")),
go.Scatter(name = "Curva",x=x, y=y,
mode="lines",
line=dict(width=2, color="blue"))],
layout=go.Layout(
xaxis=dict(range=[xm, xM], autorange=False, zeroline=False),
yaxis=dict(range=[ym, yM], autorange=False, zeroline=False),
title_text="Curva plana parametrizada", hovermode="closest",
updatemenus=[dict(type="buttons",
buttons=[dict(label="Play",
method="animate",
args=[None,{
"frame": {"duration": 20}}])])]),
frames=[go.Frame(
data=[go.Scatter(name = "Vetor tangente",
x=[x[k], x[k] + xx[k]],
y=[y[k], y[k] + yy[k]],
mode="lines+markers",
line=dict(color='red'),
marker=dict(color="red", size=20,symbol= "arrow",angleref="previous"))])
for k in range(pontos)]
)
fig.update_yaxes(scaleanchor = "x",scaleratio = 1,)
fig.show()
Show code cell source
# HIDE CODE
pontos = 300
t = np.linspace(0, 3*np.pi, pontos)
x = np.cos(t)
y = np.sin(t)
z = t
s = np.linspace(-1, 1, pontos)
u = -np.sin(t)
v = np.cos(t)
w = np.ones(pontos)
xm = np.min(np.concatenate((x,x+u))) - 4
xM = np.max(np.concatenate((x,x+u))) + 4
ym = np.min(np.concatenate((y,y+v))) - 4
yM = np.max(np.concatenate((y,y+v))) + 4
zm = np.min(np.concatenate((z,z+w))) - 4
zM = np.max(np.concatenate((z,z+w))) + 4
# Create figure
fig = go.Figure(
data=[go.Scatter3d(name = "",x=x, y=y,z=z,
mode="lines",
line=dict(width=2, color="blue")),
go.Scatter3d(),
go.Scatter3d(name = "Curva",x=x, y=y,z=z,
mode="lines",
line=dict(width=2, color="blue"))
],
layout=go.Layout(
title_text="Hélice e seus vetores tangentes", hovermode="closest",
updatemenus=#[dict(type="buttons",
# buttons=[dict(label="Play",
# method="animate",
# args=[None,{
#"frame": {"duration": 20}}])])]
[
{
"buttons": [
{
"args": [None, {"frame": {"duration": 20},
"mode": "immediate",
"fromcurrent": True,
"transition": {"duration": 20, "easing": "linear"}}],
"label": "▶", # play symbol
"method": "animate",
},
{
"args": [[None], {"frame": {"duration": 0},
"mode": "immediate",
"fromcurrent": True,
"transition": {"duration": 0, "easing": "linear"}}],
"label": "◼", # pause symbol
"method": "animate",
},
],
"direction": "left",
"pad": {"r": 10, "t": 70},
"type": "buttons",
"x": 0.1,
"y": 0,
}
]
),
frames=[go.Frame(
data=[
go.Cone(name = "Vetor tangente",
x = [x[k] + u[k]],
y = [y[k] + v[k]],
z = [z[k] + w[k]],
u = [u[k]],
v = [v[k]],
w = [w[k]],
#mode="lines+markers",
colorscale=[[1, 'red'], [1, 'red']],
showscale=False,
#marker=dict(color="red", size=20,
# symbol= "square",
#angleref="previous"
# )
),
go.Scatter3d(name = "Vetor tangente",
x = [x[k], x[k] + u[k]],
y = [y[k], y[k] + v[k]],
z = [z[k], z[k]+ w[k]],
mode = "lines",
line=dict(width=2, color="red")
)
])
for k in range(pontos)]
)
fig.update_layout(scene = dict(
xaxis = dict(nticks=4, range=[-2,2],),
yaxis = dict(nticks=4, range=[-2,2],),
zaxis = dict(nticks=4, range=[0,12],),),)
fig.show()
Show code cell source
# HIDE CODE
pontos = 360
t = np.linspace(0, 3*np.pi, pontos)
x = np.cos(t)
y = np.sin(t)
z = t
s = np.linspace(-1, 1, pontos)
u = -np.sin(t)
v = np.cos(t)
w = np.ones(pontos)
data=[]
for k in range(0,360,60):
data.append(
go.Cone(name = "Vetor tangente",
x = [x[k] + u[k]],
y = [y[k] + v[k]],
z = [z[k] + w[k]],
u = [u[k]],
v = [v[k]],
w = [w[k]],
colorscale=[[1, 'red'], [1, 'red']],
showscale=False,
)
)
data.append(
go.Scatter3d(name = "Vetor tangente",
x = [x[k], x[k] + u[k]],
y = [y[k], y[k] + v[k]],
z = [z[k], z[k]+ w[k]],
mode = "lines",
line=dict(width=2, color="red")
)
)
data.append(go.Scatter3d(name = "",x=x, y=y,z=z,
mode="lines",
line=dict(width=2, color="blue")))
fiig=go.Figure(data=data)
fiig.update_layout(showlegend=False)
fiig.show()